#pragma once
#include <iostream>
using namespace std;
#include <time.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <pthread.h>
#include <semaphore.h>

#define cap_default 10
template <class T>
class RingQueue
{
public:
    RingQueue(int cap = cap_default)
        : _cap(cap), _p_step(0), _c_step(0)
    {
        sem_init(&_blank, 0, _cap);
        sem_init(&_data, 0, 0);
        pthread_mutex_init(&pmtx, nullptr);
        pthread_mutex_init(&cmtx, nullptr);
        _rq.resize(_cap);
    }
    ~RingQueue()
    {
        sem_destroy(&_blank);
        sem_destroy(&_data);
        pthread_mutex_destroy(&pmtx);
        pthread_mutex_destroy(&cmtx);
    }

    // 生产方法
    void Push(const T &in)
    {
        // 挂起等待队列有空位置
        sem_wait(&_blank);
        // 多生产者挂互斥锁
        pthread_mutex_lock(&pmtx);
        int data = in;
        // 生产数据到规定位置
        _rq[_p_step] = data;
        _p_step++;
        _p_step %= _cap;
        //取消锁
        pthread_mutex_unlock(&pmtx);
        // 生产完增加数据资源信号量
        sem_post(&_data);
    }

    // 消费方法
    void Pop(T *out)
    {
        // 挂起等待队列有数据资源
        sem_wait(&_data);
        pthread_mutex_lock(&cmtx);
        // 消费数据
        *out = _rq[_c_step];
        _c_step++;
        _c_step %= _cap;
        pthread_mutex_unlock(&cmtx);
        // 消费完增加blank资源信号量
        sem_post(&_blank);
    }

private:
    int _cap;
    vector<T> _rq;
    sem_t _blank;
    sem_t _data;
    int _p_step;
    int _c_step;
    pthread_mutex_t pmtx;
    pthread_mutex_t cmtx;
};